var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

/**
 * Check if a value is a Promise and, if it is,
 * return the `then` method of that promise.
 *
 * @param {Promise|Any} value
 * @return {Function|Null}
 */
function getThen(value) {
    var t = typeof value;
    if (value && (t === 'object' || t === 'function')) {
        var then = value.then;
        if (typeof then === 'function') {
            return then;
        }
    }
    return null;
}

/**
 * Take a potentially misbehaving resolver function and make sure
 * onFulfilled and onRejected are only called once.
 *
 * Makes no guarantees about asynchrony.
 *
 * @param {Function} fn A resolver function that may not be trusted
 * @param {Function} onFulfilled
 * @param {Function} onRejected
 */
// 初始化时触发了被包裹的操作
function doResolve(fn, onFulfilled, onRejected) {
    var done = false;
    try {
        fn(
            // resolve
            (value) => {
                // 这里的 done 可能为 false ???
                // 这里有问题...这个 done 怎么可能赋值到对象中 ...
                if (done) return
                done = true
                onFulfilled(value)
            },
            // reject
            (reason) => {
                if (done) return
                done = true
                onRejected(reason)
            }
        )
    } catch (e) {
        if (done) return
        done = true
        onRejected(e)
    }
}

function Promise(fn) {
    // store state which can be PENDING, FULFILLED or REJECTED
    var state = PENDING;

    // store value once FULFILLED or REJECTED
    var value = null;

    // store sucess & failure handlers
    var handlers = [];

    function fulfill(result) {
        state = FULFILLED;
        value = result;
    }

    function reject(error) {
        state = REJECTED;
        value = error;
    }

    function resolve(result) {
        try {
            let then = getThen(result)
            if (then) {
                doResolve(then.bind(result), resolve, reject)
                return
            }
            fulfill(result);
        } catch (e) {
            reject(e);
        }
    }

    function handle(handler) {
        if (state === PENDING) {
            handlers.push(handler);
        } else {
            if (state === FULFILLED && typeof handler.onFulfilled === 'function') {
                handler.onFulfilled(value);
            }
            if (state === REJECTED &&
                typeof handler.onRejected === 'function') {
                handler.onRejected(value);
            }
        }
    }

    this.done = (onFulfilled, onRejected) => {
        // ensure we are always asynchronous
        setTimeout(() => {
            handle({
                onFulfilled: onFulfilled,
                onRejected: onRejected
            });
        }, 0);
    }

    this.then = function (onFulfilled, onRejected) {
        let self = this;
        return new Promise((resolve, reject) => {
            // 原来异步方法的位置
            return self.done(
                function (result) {
                    if (typeof onFulfilled === 'function') {
                        try {
                            return resolve(onFulfilled(result));
                        } catch (ex) {
                            return reject(ex);
                        }
                    } else {
                        return resolve(result);
                    }
                },
                function (error) {
                    if (typeof onRejected === 'function') {
                        try {
                            return resolve(onRejected(error));
                        } catch (ex) {
                            return reject(ex);
                        }
                    } else {
                        return reject(error);
                    }
                });
        });
    }

    doResolve(fn, resolve, reject);
}

let fs = require('fs')
// 传递一个 func 多半是需要 promise 和 异步方法本身进行交互
let p = new Promise((resolve, reject) => {
    fs.readFile('./eventloop.html', (err, res) => {
        if (err) {
            reject(err)
        } else {
            resolve(res)
        }
    })
})
p.then((result, err) => {
    console.dir(result);
})
